import os
from http import HTTPStatus
from dashscope import Application
from fastapi import APIRouter, Body, Request, Depends
from configs.other_config import DASHSCOPE_API_KEY, ALGORITHM
from configs.kb_config import GO_SERVICE_SECRET_KEY
from configs.logging_config import configure_logging
from configs.kb_prompt_mapping import KB_PROMPT_MAPPING
from configs.prompts_config import PROMPT_TEMPLATES
from server.db.models.message_model import GenericAgentChatSession
from typing import Optional, Union, Generator
from dashscope.app.application import ApplicationResponse
from server.utils import create_chat_response, BaseResponse, decode_verify_token
from loguru import logger
from sse_starlette.sse import EventSourceResponse
from server.db.session import get_db
from sqlalchemy.orm import Session
from sqlalchemy import and_
from datetime import datetime, timedelta
import asyncio
from configs.other_config import STREAM_RETURN_INTERVAL

configure_logging()
router = APIRouter()

@router.post("/bailian/v1/chat/generic_agent")
async def generic_agent_chat_v1(
    uid: str = Body(..., embed=True, description="用户ID"), 
    conversation_id: Optional[str] = Body(None, embed=True, description="会话ID"),
    stream: bool = Body(True, embed=True, description="是否流式输出"),
    app_id: str = Body(..., embed=True, description="智能体ID"),
    query: str = Body(..., embed=True, description="用户输入"),
    biz_params: Optional[dict] = Body(None, embed=True, description="业务参数(可选)"),
    memory_id: Optional[str] = Body(None, embed=True, description="记忆体ID(可选)"),
    pipeline_ids: Optional[list] = Body(None, embed=True, description="知识库ID列表(可选)，会自动根据第一个知识库ID加载对应的提示词模板"),
    request: Request = None,
    db: Session = Depends(get_db)):
    """
    通用的百炼智能体调用接口
    
    参数说明:
    - uid: 用户ID，必填
    - conversation_id: 会话ID，可选，如果提供则继续该会话
    - stream: 是否流式输出，默认True
    - app_id: 百炼智能体ID，必填
    - query: 用户输入内容，必填
    - biz_params: 业务参数，可选，用于传递给智能体的额外参数
    - memory_id: 记忆体ID，可选，如果需要使用记忆功能
    - pipeline_ids: 知识库ID列表，可选，用于RAG检索。系统会自动根据第一个知识库ID加载对应的提示词模板
    """
    
    # 解码token进行身份验证
    try:
        token = decode_verify_token(request, GO_SERVICE_SECRET_KEY, ALGORITHM)
    except Exception as e:
        logger.error(f"Token验证失败 用户ID: {uid} | 错误信息: {e}")
        return BaseResponse(
            code=401, 
            msg="Token验证失败", 
            data={"error": str(e.detail.get('msg') if hasattr(e, 'detail') else str(e))}
        )
    
    # 如果提供了知识库ID列表，自动根据第一个知识库ID加载对应的提示词模板
    if pipeline_ids and len(pipeline_ids) > 0:
        kb_id = pipeline_ids[0]  # 使用第一个知识库ID
        
        if kb_id in KB_PROMPT_MAPPING:
            prompt_template_name = KB_PROMPT_MAPPING[kb_id]
            # 从 PROMPT_TEMPLATES 中获取对应的提示词
            if "knowledge_base_chat" in PROMPT_TEMPLATES and prompt_template_name in PROMPT_TEMPLATES["knowledge_base_chat"]:
                prompt_template = PROMPT_TEMPLATES["knowledge_base_chat"][prompt_template_name]
                
                # 如果没有传递 biz_params，初始化为空字典
                if not biz_params:
                    biz_params = {}
                
                # 确保有 user_prompt_params
                if "user_prompt_params" not in biz_params:
                    biz_params["user_prompt_params"] = {}
                
                # 将提示词模板放入 biz_params
                biz_params["user_prompt_params"]["prompt"] = prompt_template
                logger.info(f"自动加载提示词模板 | 知识库ID: {kb_id} | 模板名称: {prompt_template_name} | 用户ID: {uid}")
            else:
                logger.warning(f"提示词模板未找到 | 知识库ID: {kb_id} | 模板名称: {prompt_template_name} | 用户ID: {uid}")
        else:
            logger.warning(f"知识库ID未在映射表中 | 知识库ID: {kb_id} | 用户ID: {uid}")
    
    # 会话管理：获取或创建会话ID（双重时间校验）
    session_object = db.query(GenericAgentChatSession).filter(
        and_(
            GenericAgentChatSession.user_id == uid,
            GenericAgentChatSession.app_id == app_id,
            GenericAgentChatSession.conversation_id != ""
        )
    ).order_by(GenericAgentChatSession.created_time.desc()).first()
    
    # 获取会话的首次创建时间（需要查询同会话ID的最早记录）
    first_created_time = None
    if session_object:
        first_session = db.query(GenericAgentChatSession).filter(
            GenericAgentChatSession.conversation_id == session_object.conversation_id
        ).order_by(GenericAgentChatSession.created_time.asc()).first()
        first_created_time = first_session.created_time if first_session else None
    
    # 双重时间校验
    valid_session = False
    if session_object and first_created_time:
        last_active_expired = datetime.now() - session_object.created_time > timedelta(minutes=10)
        first_create_expired = datetime.now() - first_created_time > timedelta(minutes=50)
        
        if not last_active_expired and not first_create_expired:
            valid_session = True
            conversation_id = session_object.conversation_id
        else:
            # 会话过期，标记旧会话并重置会话ID
            db.query(GenericAgentChatSession).filter(
                GenericAgentChatSession.conversation_id == session_object.conversation_id
            ).update({"is_expired": True})
            db.commit()
            conversation_id = None
            logger.info(f"会话已过期 | 用户ID: {uid} | 智能体ID: {app_id} | 旧会话ID: {session_object.conversation_id}")
    else:
        conversation_id = None
    
    # 构建调用参数
    call_params = {
        "api_key": os.getenv("DASHSCOPE_API_KEY", DASHSCOPE_API_KEY),
        "app_id": app_id,
        "prompt": query,
        "stream": stream,
    }
    
    # 如果是流式输出，启用增量输出
    if stream:
        call_params["incremental_output"] = True
    
    # 添加可选参数
    if conversation_id and valid_session:
        call_params["session_id"] = conversation_id
        logger.info(f"使用会话ID: {conversation_id} 用户ID: {uid}")
    
    if biz_params:
        call_params["biz_params"] = biz_params
        logger.info(f"使用业务参数 用户ID: {uid} | 参数: {biz_params}")
    
    if memory_id:
        call_params["memory_id"] = memory_id
        logger.info(f"使用记忆体ID: {memory_id} 用户ID: {uid}")
    
    if pipeline_ids and len(pipeline_ids) > 0:
        call_params["rag_options"] = {"pipeline_ids": pipeline_ids}
        logger.info(f"使用知识库 用户ID: {uid} | 知识库ID列表: {pipeline_ids}")
    
    logger.info(f"开始调用智能体 用户ID: {uid} | 智能体ID: {app_id} | 用户输入: {query}")
    
    try:
        responses = Application.call(**call_params)
    except Exception as e:
        logger.error(f"调用智能体异常 用户ID: {uid} | 智能体ID: {app_id} | 错误信息: {e}")
        return BaseResponse(
            code=HTTPStatus.INTERNAL_SERVER_ERROR,
            msg="调用智能体失败",
            data={
                "error_type": "500",
                "error_message": str(e),
                "uid": uid,
                "app_id": app_id,
                "query": query
            }
        )
    
    # 流式输出处理
    if stream:
        async def event_generator(responses: Union[ApplicationResponse, Generator[ApplicationResponse, None, None]]):
            full_answer = ""
            session_id = None
            request_id = None
            code = None
            
            for response in responses:
                # 检查响应状态
                if response.status_code != HTTPStatus.OK:
                    request_id = response.request_id
                    code = response.status_code
                    session_id = response.output.session_id if hasattr(response.output, 'session_id') else ""
                    
                    # 保存错误会话记录
                    session_record = GenericAgentChatSession(
                        user_id=uid,
                        app_id=app_id,
                        conversation_id=session_id,
                        request_id=request_id,
                        user_input=query,
                        pipeline_ids=",".join(pipeline_ids) if pipeline_ids else ""
                    )
                    try:
                        db.add(session_record)
                        db.commit()
                    except Exception as e:
                        db.rollback()
                        logger.error(f"保存错误会话记录失败 用户ID: {uid} | 错误信息: {e}")
                    
                    logger.error(
                        f"智能体返回错误 | 错误码: {response.code} | 错误信息: {response.message} | "
                        f"请求ID: {request_id} | 用户ID: {uid} | 会话ID: {session_id} | 用户输入: {query}"
                    )
                    
                    await asyncio.sleep(STREAM_RETURN_INTERVAL)
                    yield create_chat_response(
                        response_text=None,
                        instruction="-1",
                        request_id=request_id,
                        finish=True,
                        code=code,
                        data_content={
                            "error_type": response.code,
                            "error_message": response.message,
                            "session_id": session_id
                        }
                    )
                    return
                else:
                    # 正常响应，返回文本内容
                    answer = response.output.text
                    full_answer += answer
                    request_id = response.request_id
                    code = response.status_code
                    session_id = response.output.session_id
                    
                    await asyncio.sleep(STREAM_RETURN_INTERVAL)
                    yield create_chat_response(
                        response_text=answer,
                        instruction="-1",
                        request_id=request_id,
                        finish=False,
                        code=code,
                        data_content={"session_id": session_id}
                    )
            
            # 流式输出完成，保存会话记录
            session_record = GenericAgentChatSession(
                user_id=uid,
                app_id=app_id,
                conversation_id=session_id,
                request_id=request_id,
                user_input=query,
                assistant_answer=full_answer,
                pipeline_ids=",".join(pipeline_ids) if pipeline_ids else ""
            )
            try:
                db.add(session_record)
                db.commit()
            except Exception as e:
                db.rollback()
                logger.error(f"保存会话记录失败 用户ID: {uid} | 错误信息: {e}")
            
            logger.info(
                f"智能体调用完成 | 用户ID: {uid} | 会话ID: {session_id} | "
                f"请求ID: {request_id} | 用户输入: {query} | 智能体回答: {full_answer}"
            )
            
            await asyncio.sleep(STREAM_RETURN_INTERVAL)
            yield create_chat_response(
                response_text=full_answer,
                instruction="-1",
                request_id=request_id,
                finish=True,
                code=code,
                data_content={"session_id": session_id}
            )
        
        return EventSourceResponse(event_generator(responses))
    
    # 非流式输出处理
    else:
        if responses.status_code != HTTPStatus.OK:
            logger.error(
                f"智能体返回错误 | 错误码: {responses.code} | 错误信息: {responses.message} | "
                f"请求ID: {responses.request_id} | 用户ID: {uid} | 用户输入: {query}"
            )
            return BaseResponse(
                code=responses.status_code,
                msg=responses.message,
                data={
                    "error_type": responses.code,
                    "error_message": responses.message,
                    "uid": uid,
                    "app_id": app_id,
                    "query": query,
                    "session_id": responses.output.session_id if hasattr(responses.output, 'session_id') else ""
                }
            )
        else:
            answer = responses.output.text
            session_id = responses.output.session_id
            request_id = responses.request_id
            
            # 保存会话记录
            session_record = GenericAgentChatSession(
                user_id=uid,
                app_id=app_id,
                conversation_id=session_id,
                request_id=request_id,
                user_input=query,
                assistant_answer=answer,
                pipeline_ids=",".join(pipeline_ids) if pipeline_ids else ""
            )
            try:
                db.add(session_record)
                db.commit()
            except Exception as e:
                db.rollback()
                logger.error(f"保存会话记录失败 用户ID: {uid} | 错误信息: {e}")
            
            logger.info(
                f"智能体调用完成 | 用户ID: {uid} | 会话ID: {session_id} | "
                f"请求ID: {request_id} | 用户输入: {query} | 智能体回答: {answer}"
            )
            
            return BaseResponse(
                code=HTTPStatus.OK,
                msg="成功",
                data={
                    "uid": uid,
                    "app_id": app_id,
                    "query": query,
                    "answer": answer,
                    "session_id": session_id,
                    "request_id": request_id
                }
            )

